class Snake {
  // 表示蛇头的元素
  head: HTMLElement;
  // 蛇的身体（包括蛇头）
  body: HTMLCollection;
  // 获取蛇的容器
  element: HTMLElement;
  constructor() {
    this.element = document.getElementById("snake")!;
    this.head = document.querySelector("#snake > div")!;
    this.body = this.element.getElementsByTagName("div");
  }

  // 获取蛇的坐标（蛇头坐标）
  get X() {
    return this.head.offsetLeft;
  }
  get Y() {
    return this.head.offsetTop;
  }
  // 设置蛇头的坐标
  set X(value: number) {
    // 如果新值与旧值相同，则直接返回不在修改
    if (this.X === value) {
      return;
    }
    // X的值合法范围在0-290之间
    if (value < 0 || value > 290) {
      // 进入判断说明蛇撞墙了
      throw new Error("蛇撞墙了");
    }
    // 修改X时，不能掉头
    if (this.body[1] && (<HTMLElement>this.body[1]).offsetLeft === value) {
      // 如果发生了掉头，让蛇反方向继续移动
      if (value > this.X) {
        // 如果新值value大于旧值X，则说明蛇在向右走，此时发生掉头，应该使蛇继续向左走
        value = this.X - 10;
      } else {
        // 向左走
        value = this.X + 10;
      }
    }
    // 移动身体
    this.moveBody();
    this.head.style.left = value + "px";
    // 检查有没有撞到自己
    this.checkHeadBody();
  }
  set Y(value: number) {
    // 如果新值与旧值相同，则直接返回不在修改
    if (this.Y === value) {
      return;
    }
    // Y的值合法范围在0-290之间
    if (value < 0 || value > 290) {
      // 进入判断说明蛇撞墙了
      throw new Error("蛇撞墙了");
    }
    // 修改Y时，不能掉头
    if (this.body[1] && (<HTMLElement>this.body[1]).offsetTop === value) {
      if (value > this.Y) {
        value = this.Y - 10;
      } else {
        value = this.Y + 10;
      }
    }
    // 移动身体
    this.moveBody();
    this.head.style.top = value + "px";
    // 检查有没有撞到自己
    this.checkHeadBody();
  }

  // 蛇增加身体的方法
  addBody() {
    // 向element中添加一个div，加到最后
    this.element.insertAdjacentHTML("beforeend", "<div></div>");
  }

  // 添加一个蛇身体移动的方法
  moveBody() {
    /**
     * 将后边的身体设置为前边身体的位置
     * 举例子：
     * 第4节=第3节的位置
     * 第3节=第2节的位置
     * 第2节=蛇头的位置
     */
    // 遍历获取所有的身体
    for (let i = this.body.length - 1; i > 0; i--) {
      // 获取前边身体的位置
      let X = (<HTMLElement>this.body[i - 1]).offsetLeft;
      let Y = (<HTMLElement>this.body[i - 1]).offsetTop;

      // 将值设置到当前身体上
      (<HTMLElement>this.body[i]).style.left = X + "px";
      (<HTMLElement>this.body[i]).style.top = Y + "px";
    }
  }

  // 检查头和身体是否相撞
  checkHeadBody() {
    for (let i = 1; i < this.body.length; i++) {
      // 获取所有的身体，检查其是否和蛇头的坐标发生重叠
      const bd = this.body[i] as HTMLElement;
      if (this.X === bd.offsetLeft && this.Y === bd.offsetTop) {
        throw new Error("撞到自己了");
      }
    }
  }
}

export default Snake;
